home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / interp / tclStruct1.2.tar.gz / tclStruct1.2.tar / tclStruct1.2 / stRead.c < prev    next >
C/C++ Source or Header  |  1995-10-17  |  9KB  |  323 lines

  1. /*
  2.  *    tclStruct package
  3.  *  Support 'C' structures in Tcl
  4.  *
  5.  *  Written by Matthew Costello
  6.  *  (c) 1995 AT&T Global Information Solutions, Dayton Ohio USA
  7.  *
  8.  *  See the file "license.terms" for information on usage and
  9.  *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10.  */
  11. #include "stInternal.h"
  12. STRUCT_SCCSID("@(#)tclStruct:stRead.c    1.3    95/10/17")
  13.  
  14. #define STRUCT_READ_UNBUFFERED    0001
  15. #define STRUCT_READ_EOFOK    0002
  16. #define STRUCT_READ_MOD4    0004
  17. #define STRUCT_READ_PARTIAL    0010
  18.  
  19. #define STRUCT_READ_ERROR    0100
  20. #define STRUCT_READ_EOF        0200
  21. /*
  22.  *  Parse the two arguments:
  23.  *        object [objlen]
  24.  *  for all the functions that send or receive structure objects.
  25.  *    object    The name of the object, or a pointer to one.
  26.  *    objlen  (optional) Either a number, or the name of a variable
  27.  */
  28. int
  29. Struct_ParseObjectBuffer( interp, argc, argv, message, length, result )
  30.   Tcl_Interp *interp;
  31.   int argc;        /* I */
  32.   char **argv;        /* I */
  33.   char **message;    /* O - location of message buffer */
  34.   int *length;        /* O - length of message buffer */
  35.   char **result;    /* O - name of variable to store received length in */
  36. {
  37.     Struct_Object object;
  38.  
  39.  
  40.     if (argc < 1 || argc > 2) {
  41.     Tcl_AppendResult(interp,
  42.         "invalid number of arguments to Struct_ParseObjectBuffer",
  43.         (char *)NULL );
  44.     return TCL_ERROR;
  45.     }
  46.  
  47.     /*  If the 'result' is non-null, then we return the name of the
  48.      *  variable to store the resultant object length (on a receive).
  49.      */
  50.     if (result != NULL)
  51.     *result = NULL;
  52.  
  53.  
  54.     /*  Get the object.
  55.      */
  56.     if (Struct_GetObject( interp, argv[0], &object) != TCL_OK) {
  57.     return TCL_ERROR;
  58.     }
  59.     *message = object.data;
  60.     *length = object.size;    /* Size of object */
  61.  
  62.     /*  If an explicit message length is specified, it can either be a
  63.      *  number, or the name of a variable which contains a number.
  64.      *  If no explicit length is specified then we use the
  65.      *  size of the message buffer.
  66.      */
  67.     if (argc > 1) {
  68.     char *value;
  69.     int message_length;
  70.     if ((value = Tcl_GetVar(interp, argv[1], 0)) == NULL) {
  71.         /* Not a var, must be an integet value */
  72.         value = argv[1];
  73.     } else if (result != NULL) {
  74.         /* A variable was specified.  */
  75.         *result = argv[1];
  76.     }
  77.     if (Tcl_GetInt( interp, value, &message_length ) == TCL_ERROR) {
  78.         Struct_ReleaseType(object.type);
  79.         return TCL_ERROR;
  80.     }
  81. #ifdef DEBUG
  82.     if ((message_length > object.size) &&
  83.         !(object.type->flags & STRUCT_FLAG_VARLEN)) {
  84.         Tcl_AppendResult(interp,"length \"", argv[1],
  85.          "\" is longer than object \"", value, "\"",NULL);
  86.         Struct_ReleaseType(object.type);
  87.         return TCL_ERROR;
  88.     }
  89. #endif
  90.     *length = message_length;
  91.     }
  92.  
  93.     /*  Free up the object type now that we no longer have need of it.
  94.      */
  95.     Struct_ReleaseType(object.type);
  96.  
  97.     return TCL_OK;
  98. }
  99.  
  100.  
  101. /*
  102.  * struct_read read binary data
  103.  *    struct_read file object ?objlen?
  104.  */
  105. int
  106. Struct_ReadCmd(cdata, interp, argc, argv)
  107.   ClientData cdata;                   /* Client Data */
  108.   Tcl_Interp *interp;                 /* Current interpreter. */
  109.   int argc;                           /* Number of arguments. */
  110.   char **argv;                        /* Argument strings. */
  111. {
  112.     FILE *f;
  113.     int bytesRead;
  114.     int totalRead = 0;
  115.     char *buffer;
  116.     int length;
  117.     char *result;
  118.     int flags = 0;
  119.  
  120.     Struct_PkgInfo(cdata,si_cmdCount) += 1;
  121. #ifdef DEBUG
  122.     if (struct_debug & (DBG_COMMAND)) Struct_PrintCommand(argc,argv);
  123. #endif
  124.     for ( length = 1; length < argc && argv[length][0] == '-'; length++ ) {
  125.     if (strcmp(argv[length],"-eofok") == 0)
  126.         flags |= STRUCT_READ_EOFOK;
  127.     else if (strcmp(argv[length],"-unbuffered") == 0)
  128.         flags |= STRUCT_READ_UNBUFFERED;
  129.     else if (strcmp(argv[length],"-partial") == 0)
  130.         flags |= STRUCT_READ_PARTIAL;
  131.     else if (strcmp(argv[length],"-mod4") == 0)
  132.         flags |= STRUCT_READ_MOD4;
  133.     else {
  134.         Tcl_AppendResult(interp, "invalid flag to ", argv[0],
  135.         ": flags are -eofok, -unbuffered, and -partial",
  136.         (char *)NULL );
  137.         return TCL_ERROR;
  138.     }
  139.     }
  140.     if (argc < length+2 || argc > length+3) {
  141.     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
  142.         " ?-eofok? ?-unbuffered? ?-partial? fileId object ?objlen?\"", (char *) NULL);
  143.     return TCL_ERROR;
  144.     }
  145.     argc -= length;
  146.     argv += length;
  147.     if (Tcl_GetOpenFile(interp, argv[0], 0, 1, &f) != TCL_OK) {
  148.     return TCL_ERROR;
  149.     }
  150.  
  151.     if (Struct_ParseObjectBuffer( interp, argc-1, argv+1, &buffer, &length, &result ) == TCL_ERROR)
  152.     return TCL_ERROR;
  153.     if (flags & STRUCT_READ_MOD4)
  154.     length = (length + 3) & ~03;
  155.  
  156.     /* Continue reading from the file until we have what we
  157.      * need.  This loop is written this way so a read of '0'
  158.      * will succeed without returning a false EOF.
  159.      */
  160.     while (length > 0) {
  161.     if (flags & STRUCT_READ_UNBUFFERED) {
  162.         /* Unbuffered - raw read */
  163.         bytesRead = read(fileno(f), buffer, length);
  164.         if (bytesRead < 0)
  165.         flags |= STRUCT_READ_ERROR;
  166.         if (bytesRead == 0)
  167.         flags |= STRUCT_READ_EOF;
  168.     } else {
  169.         /* Buffered read */
  170.         clearerr(f);
  171.         bytesRead = fread(buffer, 1, length, f);
  172.         if (ferror(f))
  173.         flags |= STRUCT_READ_ERROR;
  174.         if (feof(f))
  175.            flags |= STRUCT_READ_EOF;
  176.     }
  177.  
  178.     /* Handle errors reading from the file.
  179.      */
  180.     if (flags & STRUCT_READ_ERROR) {    /* ERROR reading */
  181.         Tcl_AppendResult(interp, "error reading \"", argv[0],
  182.              "\": ", Tcl_PosixError(interp), (char *) NULL);
  183.         return TCL_ERROR;
  184.     }
  185.     if (flags & STRUCT_READ_EOF && !(flags & STRUCT_READ_EOFOK)) {
  186.         Tcl_AppendResult(interp, "unexpected EOF on \"", argv[0],
  187.              "\"", (char *) NULL);
  188.         return TCL_ERROR;
  189.     }
  190.  
  191.     /* How many have we read.
  192.      */
  193.     totalRead += bytesRead;
  194. #ifdef DEBUG
  195.     if ((bytesRead != length) && (struct_debug & (DBG_IO)))
  196.         printf("Partial read of %d bytes (wanted %d, total %d)\n",
  197.         bytesRead, length, totalRead );
  198. #endif
  199.  
  200.     /*  Update the count of the number of bytes that we
  201.      *  need to read.
  202.      */
  203.     buffer += bytesRead;
  204.     length -= bytesRead;
  205.  
  206.     /*  If partial reads are okay, then we can break out of our
  207.      *  read loop immediately.
  208.      */
  209.     if (flags & STRUCT_READ_PARTIAL)
  210.         break;
  211.     if ((flags & STRUCT_READ_EOF) && (length != 0)) {
  212.         Tcl_AppendResult(interp, "unexpected EOF on \"", argv[0],
  213.              "\" resulted in a partial read", (char *) NULL);
  214.         return TCL_ERROR;
  215.     }
  216.    }
  217.  
  218.     /* Return the number of bytes read */
  219.     sprintf( interp->result, "%d", totalRead );
  220.     if (result != NULL)
  221.     Tcl_SetVar( interp, result, interp->result, 0 );
  222.     return TCL_OK;
  223. }
  224.  
  225. /*
  226.  * struct_write write binary data
  227.  *    struct_write file object ?objlen?
  228.  */
  229. int
  230. Struct_WriteCmd(cdata, interp, argc, argv)
  231.   ClientData cdata;                   /* Client Data */
  232.   Tcl_Interp *interp;                 /* Current interpreter. */
  233.   int argc;                           /* Number of arguments. */
  234.   char **argv;                        /* Argument strings. */
  235. {
  236.     FILE *f;
  237.     int bytesWritten;
  238.     int totalWritten = 0;
  239.     char *buffer;
  240.     int length;
  241.     char *result;
  242.     int flags = 0;
  243.  
  244.     Struct_PkgInfo(cdata,si_cmdCount) += 1;
  245. #ifdef DEBUG
  246.     if (struct_debug & (DBG_COMMAND)) Struct_PrintCommand(argc,argv);
  247. #endif
  248.     for ( length = 1; length < argc && argv[length][0] == '-'; length++ ) {
  249.     if (strcmp(argv[length],"-unbuffered") == 0)
  250.         flags |= STRUCT_READ_UNBUFFERED;
  251.     else if (strcmp(argv[length],"-partial") == 0)
  252.         flags |= STRUCT_READ_PARTIAL;
  253.     else if (strcmp(argv[length],"-mod4") == 0)
  254.         flags |= STRUCT_READ_MOD4;
  255.     else {
  256.         Tcl_AppendResult(interp, "invalid flag to ", argv[0],
  257.         ": flags are -eofok, -unbuffered, and -partial",
  258.         (char *)NULL );
  259.         return TCL_ERROR;
  260.     }
  261.     }
  262.     if (argc < length+2 || argc > length+3) {
  263.     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
  264.         " fileId object ?objlen?\"", (char *) NULL);
  265.     return TCL_ERROR;
  266.     }
  267.     argc -= length;
  268.     argv += length;
  269.     if (Tcl_GetOpenFile(interp, argv[0], 1, 1, &f) != TCL_OK) {
  270.     return TCL_ERROR;
  271.     }
  272.  
  273.     if (Struct_ParseObjectBuffer( interp, argc-1, argv+1, &buffer, &length, &result ) == TCL_ERROR)
  274.     return TCL_ERROR;
  275.     if (flags & STRUCT_READ_MOD4)
  276.     length = (length + 3) & ~03;
  277.  
  278.     /* Continue writing from the file until we have written
  279.      * everything.  This loop is written this way so a write
  280.      * of '0' will not do anything.
  281.      */
  282.     while (length > 0) {
  283.     if (flags & STRUCT_READ_UNBUFFERED) {
  284.         /* Unbuffered - raw write */
  285.         bytesWritten = write(fileno(f), buffer, length);
  286.         if (bytesWritten < 0)
  287.         flags |= STRUCT_READ_ERROR;
  288.     } else {
  289.         /* Buffered write */
  290.         clearerr(f);
  291.         bytesWritten = fwrite(buffer, 1, length, f);
  292.         if (ferror(f))
  293.         flags |= STRUCT_READ_ERROR;
  294.     }
  295.  
  296.     /* Handle errors */
  297.     if (flags & STRUCT_READ_ERROR) {    /* ERROR writeing */
  298.         Tcl_AppendResult(interp, "error writing \"", argv[0],
  299.              "\": ", Tcl_PosixError(interp), (char *) NULL);
  300.         return TCL_ERROR;
  301.     }
  302.  
  303.     /* How many have we written so far. */
  304.     totalWritten += bytesWritten;
  305. #ifdef DEBUG
  306.     if ((bytesWritten != length) && (struct_debug & (DBG_IO)))
  307.         printf("Partial write of %d bytes (wanted %d, total %d)\n",
  308.         bytesWritten, length, totalWritten );
  309. #endif
  310.     if (flags & STRUCT_READ_PARTIAL)
  311.         break;
  312.     buffer += bytesWritten;
  313.     length -= bytesWritten;
  314.     }
  315.  
  316.     /* Return the number of bytes written */
  317.     sprintf( interp->result, "%d", totalWritten );
  318.     if (result != NULL)
  319.     Tcl_SetVar( interp, result, interp->result, 0 );
  320.     return TCL_OK;
  321. }
  322.  
  323.